package com.andova.camera.texture

import android.graphics.Bitmap
import android.graphics.SurfaceTexture
import android.opengl.GLES30
import com.andova.ext.i
import com.andova.ext.printCounter
import com.andova.glcamera.texture.TextureFrameCallback
import com.andova.image.GLES.Companion.glReadPixels
import java.nio.ByteBuffer
import java.nio.ByteOrder

@Deprecated("")
class ASampleProvider : TextureFrameCallback {
    override fun onSurfaceSizeChanged(width: Int, height: Int) {
        GLES30.glViewport(0, 0, width, height)
    }

    override fun onSurfaceDestroyed(surfaceTexture: SurfaceTexture?) {
        drawer.unregister()
    }

    private var matLoc = -1
    private var samLoc = -1
    private var width = -1
    private var height = -1
    private val drawer = Drawer()
    override fun onSurfaceAvailable(width: Int, height: Int) {
        this.width = width
        this.height = height
        drawer.register(width, height)
//        GLES30.glUseProgram(parameter.oesProgramId)
        GLES30.glViewport(0, 0, width, height)
        i(GLES30.glGetString(GLES30.GL_EXTENSIONS))
//        matLoc = GLES30.glGetUniformLocation(parameter.oesProgramId, "uTexMat")
//        samLoc = GLES30.glGetUniformLocation(parameter.oesProgramId, "yuvTexSampler")
    }

    override fun onTaskFrame(imageWidth: Int, imageHeight: Int, nv21: ByteArray, handlerResult: Any?) {
        printCounter("onFrameData")
        readFrame(imageWidth, imageHeight)
    }

    /**
     * 该方法必须在glDraw方法后执行才有效
     * todo 修复图像颠倒的问题
     * 这样直接调用，glReadPixels耗时很多
     */
    private fun readFrame(width: Int = this.width, height: Int = this.height) {
        val buffer: ByteBuffer = ByteBuffer.allocate(width * height * 4) // 一个argb像素含4字节
        val dt = System.currentTimeMillis()
        GLES30.glReadPixels(0, 0, width, height, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, buffer)
        i("time millis -> ${System.currentTimeMillis() - dt}")
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        buffer.rewind()
        bitmap.copyPixelsFromBuffer(buffer)
        bitmap?.recycle()
    }

    internal class Drawer {
        companion object {
            const val FLOAT_BYTE = 4
            val BUFFER_DATA = floatArrayOf(
                    -1f, -1f, 0f, 0f,
                    1f, -1f, 1f, 0f,
                    1f, 1f, 1f, 1f,
                    -1f, 1f, 0f, 1f
            )
            const val STRIDE_POSITION = 4 * FLOAT_BYTE
            const val STRIDE_TEXTURE = 2 * FLOAT_BYTE
        }

        private val boBuffers = IntArray(3)

        fun register(width: Int, height: Int) {
            GLES30.glGenBuffers(3, boBuffers, 0)
            val bytes = BUFFER_DATA.size * FLOAT_BYTE
            val buffer = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer().put(BUFFER_DATA).position(0)

            // VBO
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, boBuffers[0])
            GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, BUFFER_DATA.size * FLOAT_BYTE, buffer, GLES30.GL_STATIC_DRAW)
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, GLES30.GL_NONE)

            // PBO 1
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, boBuffers[1])
            GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, width * height * Int.SIZE_BYTES, null, GLES30.GL_STREAM_READ)
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, GLES30.GL_NONE)

            // PBO 2
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, boBuffers[2])
            GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, width * height * Int.SIZE_BYTES, null, GLES30.GL_STREAM_READ)
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, GLES30.GL_NONE)
        }

        fun unregister() {
            GLES30.glDeleteBuffers(GLES30.GL_ARRAY_BUFFER, boBuffers, 0)
        }

        fun drawFrameByNormal(vertexLoc: Int, textureLoc: Int) {
            val vertexData = floatArrayOf(
                    -1f, -1f,
                    1f, -1f,
                    1f, 1f,
                    -1f, 1f
            )
            val vertexBuffer = ByteBuffer.allocateDirect(vertexData.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData).position(0)

            val texPosData = floatArrayOf(
                    0f, 0f,
                    1f, 0f,
                    1f, 1f,
                    0f, 1f
            )
            val texPosBuffer = ByteBuffer.allocateDirect(texPosData.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(texPosData).position(0)

            GLES30.glEnableVertexAttribArray(vertexLoc)
            GLES30.glVertexAttribPointer(vertexLoc, 2, GLES30.GL_FLOAT, false, 0, vertexBuffer)
            GLES30.glEnableVertexAttribArray(textureLoc)
            GLES30.glVertexAttribPointer(textureLoc, 2, GLES30.GL_FLOAT, false, 0, texPosBuffer)
            GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4)
            GLES30.glDisableVertexAttribArray(vertexLoc)
            GLES30.glDisableVertexAttribArray(textureLoc)
        }

        fun drawFrameByVBO(vertexLoc: Int, textureLoc: Int) {
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, boBuffers[0])
            GLES30.glEnableVertexAttribArray(vertexLoc)
            GLES30.glEnableVertexAttribArray(textureLoc)

            GLES30.glVertexAttribPointer(vertexLoc, 2, GLES30.GL_FLOAT, false, STRIDE_POSITION, 0)
            GLES30.glVertexAttribPointer(textureLoc, 2, GLES30.GL_FLOAT, false, STRIDE_POSITION, STRIDE_TEXTURE)
            GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4)

            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, GLES30.GL_NONE)
            GLES30.glDisableVertexAttribArray(vertexLoc)
            GLES30.glDisableVertexAttribArray(textureLoc)
        }

        private var pbo1Index = 1
        private var pbo2Index = 2

        /**
         * 单单只是这样的话，glReadPixels和glMapBufferRange耗时确实低了，但预览画面还是很卡
         */
        fun readFrame(width: Int, height: Int) {
//            printDelay("readFrame")
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, boBuffers[pbo1Index])
            val dt = System.currentTimeMillis()
            glReadPixels(width, height)
            i("glReadPixels time millis -> ${System.currentTimeMillis() - dt}")
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, boBuffers[pbo2Index])
            val pixelBuffer = GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, width * height * Int.SIZE_BYTES, GLES30.GL_MAP_READ_BIT)
            i("glMapBufferRange time millis -> ${System.currentTimeMillis() - dt}")
            pixelBuffer?.run {
                rewind()
                val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
                bitmap.copyPixelsFromBuffer(this)
                bitmap?.recycle()
            }
            GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER)
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, GLES30.GL_NONE)
            pbo1Index %= 2
            ++pbo1Index
            pbo2Index %= 2
            ++pbo2Index
            i("pbo1Index:$pbo1Index,pbo2Index:$pbo2Index")
        }
    }
}